using System.Text;
using System.Text.Json;
using Order.Api.Read.Dto.Order;

namespace Order.Api.Read.Service.MedicalAIService
{
    /// <summary>
    /// Ollama AI服务实现类
    /// 负责与本地Ollama服务进行通信，提供医疗AI功能
    /// 包括处方分析、诊断建议、药品相互作用检查等
    /// </summary>
    public class OllamaAIService : IMedicalAIService
    {
        /// <summary>
        /// HTTP客户端，用于与Ollama API通信
        /// </summary>
        private readonly HttpClient _httpClient;

        /// <summary>
        /// 日志记录器，用于记录AI服务的运行状态和错误信息
        /// </summary>
        private readonly ILogger<OllamaAIService> _logger;

        /// <summary>
        /// Ollama服务的API基础URL
        /// </summary>
        private const string OLLAMA_URL = "http://127.0.0.1:11434/api";

        /// <summary>
        /// 使用的AI模型名称
        /// </summary>
        private const string MODEL_NAME = "deepseek-r1:8b";

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="httpClient">HTTP客户端实例</param>
        /// <param name="logger">日志记录器实例</param>
        public OllamaAIService(HttpClient httpClient, ILogger<OllamaAIService> logger)
        {
            _httpClient = httpClient;
            _logger = logger;

            // 设置更长的超时时间，因为AI生成可能需要较长时间
            _httpClient.Timeout = TimeSpan.FromMinutes(5);
        }

        /// <summary>
        /// 生成AI响应的核心方法
        /// 负责构建请求、发送到Ollama API、解析响应并处理错误
        /// </summary>
        /// <param name="prompt">发送给AI的提示文本</param>
        /// <returns>AI生成的响应文本</returns>
        private async Task<string> GenerateResponseAsync(string prompt)
        {
            try
            {
                // 记录开始调用AI服务
                _logger.LogInformation($"开始调用Ollama API，模型：{MODEL_NAME}");

                // 构建Ollama API请求对象
                var request = new
                {
                    model = MODEL_NAME,        // 指定使用的模型
                    prompt = prompt,           // 用户输入的提示
                    stream = false,            // 不使用流式响应
                    options = new
                    {
                        temperature = 0.7,    // 控制响应的随机性，0.7为中等创造性
                        top_p = 0.9,          // 核采样参数，控制词汇选择的多样性
                        max_tokens = 2048     // 最大生成token数量
                    }
                };

                // 序列化请求对象为JSON
                var json = JsonSerializer.Serialize(request);
                var content = new StringContent(json, Encoding.UTF8, "application/json");

                // 记录发送请求
                _logger.LogInformation($"发送请求到：{OLLAMA_URL}/generate");
                var response = await _httpClient.PostAsync($"{OLLAMA_URL}/generate", content);

                // 记录响应状态
                _logger.LogInformation($"收到响应，状态码：{response.StatusCode}");

                // 检查HTTP响应是否成功
                if (response.IsSuccessStatusCode)
                {
                    // 读取响应内容
                    var responseContent = await response.Content.ReadAsStringAsync();
                    _logger.LogInformation($"响应内容：{responseContent}");

                    try
                    {
                        // 配置JSON反序列化选项，处理Unicode转义字符
                        var options = new JsonSerializerOptions
                        {
                            PropertyNameCaseInsensitive = true,  // 忽略属性名大小写
                            Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping  // 处理Unicode转义
                        };

                        // 尝试反序列化响应
                        var result = JsonSerializer.Deserialize<OllamaResponse>(responseContent, options);
                        if (result != null && !string.IsNullOrWhiteSpace(result.Response))
                        {
                            _logger.LogInformation("AI响应解析成功");
                            return result.Response;
                        }
                        else
                        {
                            _logger.LogWarning("AI响应为空或解析失败");
                            // 备用方案：尝试手动解析response字段
                            try
                            {
                                var jsonDoc = JsonDocument.Parse(responseContent);
                                if (jsonDoc.RootElement.TryGetProperty("response", out var responseElement))
                                {
                                    var responseText = responseElement.GetString();
                                    if (!string.IsNullOrWhiteSpace(responseText))
                                    {
                                        _logger.LogInformation("手动解析AI响应成功");
                                        return responseText;
                                    }
                                }
                            }
                            catch (Exception manualEx)
                            {
                                _logger.LogError(manualEx, "手动解析也失败");
                            }
                            return "AI服务响应为空，请稍后重试";
                        }
                    }
                    catch (JsonException jsonEx)
                    {
                        _logger.LogError(jsonEx, "JSON反序列化失败");
                        // 备用方案：尝试手动解析response字段
                        try
                        {
                            var jsonDoc = JsonDocument.Parse(responseContent);
                            if (jsonDoc.RootElement.TryGetProperty("response", out var responseElement))
                            {
                                var responseText = responseElement.GetString();
                                if (!string.IsNullOrWhiteSpace(responseText))
                                {
                                    _logger.LogInformation("手动解析AI响应成功");
                                    return responseText;
                                }
                            }
                        }
                        catch (Exception manualEx)
                        {
                            _logger.LogError(manualEx, "手动解析也失败");
                        }
                        return "AI服务响应格式错误，请稍后重试";
                    }
                }
                else
                {
                    // HTTP请求失败，记录错误信息
                    var errorContent = await response.Content.ReadAsStringAsync();
                    _logger.LogError($"Ollama API调用失败: {response.StatusCode}, 错误内容: {errorContent}");
                    return $"AI服务调用失败: {response.StatusCode}";
                }
            }
            catch (HttpRequestException httpEx)
            {
                // 网络连接异常
                _logger.LogError(httpEx, "HTTP请求异常");
                return "AI服务连接失败，请检查Ollama服务是否正常运行";
            }
            catch (TaskCanceledException timeoutEx)
            {
                // 请求超时异常
                _logger.LogError(timeoutEx, "请求超时");
                return "AI服务响应超时，请稍后重试";
            }
            catch (Exception ex)
            {
                // 其他未知异常
                _logger.LogError(ex, "调用Ollama AI服务时发生未知错误");
                return "AI服务暂时不可用，请稍后重试";
            }
        }

        /// <summary>
        /// 测试AI服务连接状态
        /// 通过发送简单的"Hello"消息来验证服务是否可用
        /// </summary>
        /// <returns>true表示连接正常，false表示连接失败</returns>
        public async Task<bool> TestConnectionAsync()
        {
            try
            {
                // 发送简单的测试消息
                var result = await GenerateResponseAsync("Hello");
                // 检查响应中是否包含错误关键词
                return !result.Contains("失败") && !result.Contains("不可用") && !result.Contains("错误");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "测试AI服务连接失败");
                return false;
            }
        }
         
        /// <summary>
        /// 分析处方内容
        /// 对输入的处方文本进行专业分析，提供用药建议
        /// </summary>
        /// <param name="prescriptionText">处方文本内容</param>
        /// <returns>AI生成的处方分析结果</returns>
        public async Task<string> AnalyzePrescriptionAsync(string prescriptionText)
        {
            // 构建专业的处方分析提示 
            var prompt = $@"请分析以下处方内容，并提供专业的医疗建议：

处方内容：{prescriptionText}

请从以下方面进行分析：
1. 药品配伍是否合理
2. 用药剂量是否适当
3. 是否存在潜在的药物相互作用
4. 对患者的用药建议
5. 需要注意的副作用

请用中文回答，格式要清晰易读。";

            return await GenerateResponseAsync(prompt);
        }

        /// <summary>
        /// 生成医疗报告
        /// 根据患者信息和订单数据生成专业的医疗报告
        /// </summary>
        /// <param name="patient">患者信息</param>
        /// <param name="orderData">订单数据</param>
        /// <returns>生成的医疗报告</returns>
        public async Task<string> GenerateMedicalReportAsync(PatientDto patient, object orderData)
        {
            // 序列化患者信息和订单数据
            var patientInfo = JsonSerializer.Serialize(patient);
            var orderInfo = JsonSerializer.Serialize(orderData);

            // 构建医疗报告生成提示
            var prompt = $@"请根据以下患者信息和订单数据生成一份专业的医疗报告：

患者信息：{patientInfo}
订单数据：{orderInfo}

请生成包含以下内容的报告：
1. 患者基本信息总结
2. 订单类型和状态分析
3. 医疗建议和注意事项
4. 后续随访建议

请用中文回答，格式要专业规范。";

            return await GenerateResponseAsync(prompt);
        }

        /// <summary>
        /// 获取诊断建议
        /// 根据症状描述和患者病史提供初步诊断建议
        /// </summary>
        /// <param name="symptoms">症状描述</param>
        /// <param name="patientHistory">患者病史</param>
        /// <returns>AI生成的诊断建议</returns>
        public async Task<string> GetDiagnosticSuggestionAsync(string symptoms, string patientHistory)
        {
            // 构建诊断建议提示
            var prompt = $@"请根据以下症状和病史提供初步诊断建议：

症状描述：{symptoms}
患者病史：{patientHistory}

请提供：
1. 可能的诊断方向
2. 建议的检查项目
3. 需要注意的警示症状
4. 初步治疗建议

注意：这只是AI辅助建议，最终诊断需要专业医生确认。";

            return await GenerateResponseAsync(prompt);
        }

        /// <summary>
        /// 检查药品相互作用
        /// 分析多个药品之间是否存在相互作用
        /// </summary>
        /// <param name="drugList">药品列表</param>
        /// <returns>药品相互作用分析结果</returns>
        public async Task<string> CheckDrugInteractionsAsync(List<string> drugList)
        {
            // 将药品列表转换为字符串
            var drugs = string.Join("、", drugList);

            // 构建药品相互作用检查提示
            var prompt = $@"请检查以下药品之间是否存在相互作用：

药品列表：{drugs}

请分析：
1. 是否存在药物相互作用
2. 相互作用的严重程度
3. 建议的用药间隔
4. 需要特别注意的副作用
5. 替代用药建议

请用中文回答，格式要清晰。";

            return await GenerateResponseAsync(prompt);
        }

        /// <summary>
        /// 生成健康建议
        /// 根据患者信息和订单历史生成个性化的健康建议
        /// </summary>
        /// <param name="patient">患者信息</param>
        /// <param name="orderHistory">订单历史</param>
        /// <returns>个性化的健康建议</returns>
        public async Task<string> GenerateHealthAdviceAsync(PatientDto patient, List<object> orderHistory)
        {
            // 序列化患者信息和订单历史
            var patientInfo = JsonSerializer.Serialize(patient);
            var historyInfo = JsonSerializer.Serialize(orderHistory);

            // 构建健康建议生成提示
            var prompt = $@"请根据以下患者信息和订单历史生成个性化的健康建议：

患者信息：{patientInfo}
订单历史：{historyInfo}

请提供：
1. 基于病史的健康风险评估
2. 个性化的生活方式建议
3. 预防性保健建议
4. 定期体检建议
5. 紧急情况处理指导

请用中文回答，建议要具体实用。";

            return await GenerateResponseAsync(prompt);
        }
    }

    /// <summary>
    /// Ollama API响应模型
    /// 用于反序列化Ollama API返回的JSON响应
    /// </summary>
    public class OllamaResponse
    {
        /// <summary>
        /// 使用的模型名称
        /// </summary>
        public string Model { get; set; } = "";

        /// <summary>
        /// AI生成的响应文本
        /// </summary>
        public string Response { get; set; } = "";

        /// <summary>
        /// 响应创建时间戳
        /// </summary>
        public long CreatedAt { get; set; }

        /// <summary>
        /// 是否完成生成
        /// </summary>
        public bool Done { get; set; }

        /// <summary>
        /// 总处理时间（纳秒）
        /// </summary>
        public long TotalDuration { get; set; }

        /// <summary>
        /// 模型加载时间（纳秒）
        /// </summary>
        public long LoadDuration { get; set; }

        /// <summary>
        /// 提示词评估次数
        /// </summary>
        public long PromptEvalCount { get; set; }

        /// <summary>
        /// 提示词评估时间（纳秒）
        /// </summary>
        public long PromptEvalDuration { get; set; }

        /// <summary>
        /// 生成token数量
        /// </summary>
        public long EvalCount { get; set; }

        /// <summary>
        /// 生成时间（纳秒）
        /// </summary>
        public long EvalDuration { get; set; }
    }
}